// 赋值运算符函数
// 1. 把返回值的类型声明为该类型的引用，并在函数结束前返回实例自身的引用。这样才可以连续赋值
// 2. 把传入的参数的类型声明为常量引用
// 3. 释放实例自身已有的内存
// 4. 判断传入的参数和当前的实例是不是同一个实例
#include<cstring>
#include<cstdio>

class CMyString {
  public:
    CMyString(char* pData = nullptr);
    CMyString(const CMyString& str);
    ~CMyString();

    CMyString& operator = (const CMyString& str);
    CMyString& operator1(const CMyString& str);

    void Print();

  private:
    char* m_pData;
};

CMyString::CMyString(char *pData) {
  if (pData == nullptr) {
    m_pData = new char[1];
    m_pData[0] = '\0';
  } else {
    int length = strlen(pData);
    m_pData = new char[length + 1];
    strcpy(m_pData, pData);
  }
}

CMyString::CMyString(const CMyString &str) {
  int length = strlen(str.m_pData);
  m_pData = new char[length + 1];
  strcpy(m_pData, str.m_pData);
}

CMyString::~CMyString() {
  delete[] m_pData;
}

CMyString& CMyString::operator = (const CMyString& str) {
  if (this == &str) {
    return *this;
  }

  delete[] m_pData;
  m_pData = nullptr;

  m_pData = new char[strlen(str.m_pData) + 1];
  strcpy(m_pData, str.m_pData);

  return *this;
}

// 如果内存不足导致new char抛出异常，则m_pData是一个空指针。
// 有两种解决方法：
// 1. 先用new分配内存，再用delete释放内存
// 2. 先创建一个临时实例，再交换临时实例和原来的实例
CMyString& CMyString::operator1(const CMyString& str) {
  if (this != &str) {
    CMyString strTemp(str);

    char* pTemp = strTemp.m_pData;
    strTemp.m_pData = m_pData;
    m_pData = pTemp;
  }
  return *this;
}

void CMyString::Print() {
  printf("%s", m_pData);
}

int main() {
  char* text = "hello, world";

  CMyString str1(text);
  CMyString str2;
  str2 = str1;

  printf("The expected result is: %s.\n", text);
  printf("The actual result is: ");
  str2.Print();
  printf(".\n");

  return 0;
}
